package io.persimmon.core.module.lock.local;

import io.persimmon.core.module.lock.Lock;
import io.persimmon.core.module.lock.constant.LockResult;
import io.persimmon.core.module.lock.constant.UnLockResult;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 基于ReentrantLock的字符串加锁工具类
 * 特性：相同字符串对应同一把锁，支持可中断、超时获取锁，自动清理未使用的锁
 */
@Slf4j
public class StringReentrantLock implements Lock {
    // 存储"字符串→锁对象"的映射，Value为锁对象+引用计数
    private static final Map<String, LockInfo> lockMap = new ConcurrentHashMap<>();

    /**
     * 获取锁（不可中断）
     *
     * @param key 字符串键
     */
    public void lock(String key) {
        // 1. 获取或创建锁对象，引用计数+1
        LockInfo lockInfo = getOrCreateLockInfo(key);
        try {
            // 2. 获取锁（阻塞直到成功）
            lockInfo.lock.lock();
        } catch (Exception e) {
            // 异常时减少引用计数
            releaseLockInfo(key, lockInfo);
            throw e;
        }
    }

    @Override
    public LockResult tryLock(String key, long waitMills) throws Exception {
        LockInfo lockInfo = getOrCreateLockInfo(key);
        try {
            // 尝试在超时时间内获取锁
            boolean b = lockInfo.lock.tryLock(waitMills, TimeUnit.MILLISECONDS);
            if (!b) {
                return LockResult.LOCK_EXIST;
            }
            return LockResult.SUCCESS;
        } catch (InterruptedException e) {
            throw e;
        }
    }


    @Override
    public UnLockResult unLock(String key) {
        if (!this.isHeldByCurrentThread(key)) {
            return UnLockResult.LOCK_NOT_CURRENT_THREAD;
        }
        LockInfo lockInfo = lockMap.get(key);
        if (lockInfo == null) {
            return UnLockResult.LOCK_NOT_EXIST;
        }

        // 1. 释放锁
        lockInfo.lock.unlock();
        // 2. 减少引用计数，若为0则从map中移除
        releaseLockInfo(key, lockInfo);
        return UnLockResult.SUCCESS;
    }

    /**
     * 获取或创建锁对象，并增加引用计数
     */
    private LockInfo getOrCreateLockInfo(String key) {
        // 确保相同key对应同一个LockInfo（ConcurrentHashMap线程安全）
        LockInfo lockInfo = lockMap.computeIfAbsent(key, k -> new LockInfo());
        // 引用计数+1（原子操作，线程安全）
        int count = lockInfo.refCount.incrementAndGet();
        return lockInfo;
    }

    /**
     * 减少引用计数，若为0则移除锁对象
     */
    private void releaseLockInfo(String key, LockInfo lockInfo) {
        if (lockInfo.refCount.decrementAndGet() == 0) {
            // 引用计数为0，从map中移除（避免内存泄漏）
            lockMap.remove(key);
        }
    }

    /**
     * 检查当前线程是否持有该key的锁
     */
    public boolean isHeldByCurrentThread(String key) {
        LockInfo lockInfo = lockMap.get(key);
        return lockInfo != null && lockInfo.lock.isHeldByCurrentThread();
    }

    /**
     * 锁信息包装类：包含ReentrantLock和引用计数
     */
    private static class LockInfo {
        final ReentrantLock lock = new ReentrantLock(); // 可重入锁
        final AtomicInteger refCount = new AtomicInteger(0); // 引用计数
    }
}
